<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title>文件系统</title>
  <style type="text/css">code{white-space: pre;}</style>
  <style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
  </style>
  <link rel="stylesheet" href="doc/linux-style.css" type="text/css" />
</head>
<body>
<div id="header">
<h1 class="title">文件系统</h1>
</div>
<div id="TOC">
<ul>
<li><a href="#文件系统">文件系统</a><ul>
<li><a href="#虚拟文件系统">虚拟文件系统</a></li>
<li><a href="#nfs文件系统">nfs文件系统</a></li>
<li><a href="#smb文件系统">smb文件系统</a></li>
<li><a href="#ext2文件系统">ext2文件系统</a></li>
</ul></li>
</ul>
</div>
<h1 id="文件系统">文件系统</h1>
<p>文件系统是什么？举个例子，比如我们存储一些信息，肯定需要硬盘，那么存储的方法有两种，其中一种则是从第一个字节、第二个字节以此类推。第二种方法是先创建一个文件，在这个文件里存储这句话，我们打开硬盘时，只需要找到这个文件的位置，就能找到这个内容。</p>
<p>文件系统就是一种管理数据的规则。</p>
<p>文件系统下面有好几种文件系统： - 磁盘文件系统，如ext2、ext4、xfs、ntfs等。 - 网络文件系统，如nfs、cifs等。 - 特殊文件系统，如procfs、sysfs等。</p>
<p>这里用主线内核代码和4.19分支的代码举个例子：</p>
<p>主线最新目录结构:</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash"><span class="ex">.</span>
├── <span class="ex">fs</span>
│   ├── <span class="ex">nfs</span> <span class="co"># nfs客户端代码</span>
│   ├── <span class="ex">nfsd</span> <span class="co"># nfs服务端代码</span>
│   ├── <span class="ex">nfs_common</span>  # nfs公共端代码
│   ├── <span class="ex">smb</span>  
        ├── <span class="ex">client</span>  # smb客户端代码
        ├── <span class="ex">common</span>  # smb公共端代码
        ├── <span class="ex">server</span>  # smb服务端代码 曾经是fs/cifsd和fs/ksmbd
│   ├── <span class="ex">ntfs3</span>    #Linux 5.15才将ntfs3合并到内核里面</code></pre></div>
<p>4.19目录结构:</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash"><span class="ex">.</span>
├── <span class="ex">fs</span>
│   ├── <span class="ex">nfs</span> <span class="co"># nfs客户端代码</span>
│   ├── <span class="ex">nfsd</span> <span class="co"># nfs服务端代码</span>
│   ├── <span class="ex">nfs_common</span>  # nfs公共端代码
│   ├── <span class="ex">cifs</span>      #主线最新代码的smb/client
│   ├── <span class="ex">ntfs</span>  #老旧的 ntfs 驱动功能非常有限</code></pre></div>
<p>可以在最新的源码上用<code>git log --oneline -- fs/ksmbd</code> 查看ksmbd的提交记录 'git show --stat <commit-id>'可以查看某个文件修改的统计</p>
<p>fs/ksmd -&gt; fs/smb/server 出现在这个提交记录上：38c8a9a52082 smb: move client and server files to common directory fs/smb</p>
<p>fs/cifsd -&gt; fs/ksmd 出现在这个提交记录上：1a93084b9a89 ksmbd: move fs/cifsd to fs/ksmbd</p>
<p>4534a70b7056 2021-08-13 fs/ntfs3: Add headers and misc files #第一次提交ntfs3的代码</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash"><span class="co"># 查看d文件的最近一次重命名提交</span>
<span class="fu">git</span> log --follow --diff-filter=R --name-status -1 -- d
<span class="co"># 查看c文件的最近一次重命名提交</span>
<span class="fu">git</span> log --follow --diff-filter=R --name-status -1 -- c
<span class="co"># 查看b文件的最近一次重命名提交</span>
<span class="fu">git</span> log --follow --diff-filter=R --name-status -1 -- b

<span class="co"># 一次性查看完整重命名历史（按时间倒序）</span>
<span class="fu">git</span> log --follow --name-status -- d</code></pre></div>
<p>如何查看一个函数的第一次提交记录：</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash"><span class="co">#拿smb2_parse_contexts这个函数举例子</span>
<span class="bu">cd</span>  主线分支
<span class="fu">git</span> blame fs/smb/client/smb2pdu.c <span class="kw">|</span> <span class="fu">grep</span> smb2_parse_contexts  #会弹出commit-id 找到定义函数的commit-id
<span class="fu">git</span> show  <span class="op">&lt;</span>commit-id<span class="op">&gt;</span>                #查看这个commit是否是第一次提交
<span class="fu">git</span> log --oneline  <span class="op">&lt;</span>commit-id<span class="op">&gt;</span>       #如果不是第一次提交，查看这个commit-id的前一个提交
<span class="fu">git</span> checkout <span class="op">&lt;</span>commit-id<span class="op">&gt;</span>             #回退到之前版本
<span class="co">#然后再重复第二个步骤</span></code></pre></div>
<p>实际操作一下第二种存储方式的文件系统</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash"><span class="ex">fallocate</span> -l 1G 1
<span class="ex">mkfs.ext4</span> -F /dev/sda           # 格式化文件系统
<span class="fu">mount</span> -t ext4 /dev/sda /mnt     # 把磁盘挂载到某个目录
<span class="fu">df</span> /dev/sda <span class="co"># 查看是否已经挂载上</span>
<span class="bu">echo</span> <span class="st">&quot;我爱操作系统&quot;</span> <span class="op">&gt;</span> /mnt/file   # 存到挂载点下的某个文件中
<span class="fu">cat</span> /mnt/file                   # 输出文件内容
<span class="ex">debugfs</span> /dev/sda
<span class="co"># debugfs:  stats # Block size: 1024</span>
<span class="co"># debugfs:  stat file # BLOCKS: (0):7169</span>
<span class="fu">dd</span> if=/dev/sda of=./data bs=1 skip=7341056 count=20  #具体的skip=多少需要根据Block size 和BLOCKS计算
<span class="fu">cat</span> data
<span class="fu">umount</span> /mnt                     # 卸载文件系统</code></pre></div>
<h2 id="虚拟文件系统">虚拟文件系统</h2>
<p>所有的文件系统都需要经过这虚拟文件系统层，就相当于制定了一套规则，你必须按照这种格式给我提供接口，封装。</p>
<p>可以看看虚拟文件系统封装了哪些重要的对象；</p>
<p><strong>1 超级块对象</strong></p>
<p>超级块，超级块是对一个文件系统的描述；存储特定文件系统的信息。如果是基于磁盘的文件系统，通常对应磁盘上特定扇区中的数据。如果不是基于磁盘的文件系统（如procfs或sysfs），会在使用时创建超级块，只保留在内存中。 超级块对象结构体定义在文件include/linux/fs.h中。</p>
<p><strong>2 超级块操作</strong></p>
<p>超级块也封装了一些操作。超级块操作函数表结构体也是定义在文件include/linux/fs.h中。</p>
<p><strong>3 索引节点</strong></p>
<p>索引节点inode是对一个文件物理属性的描述，操作文件和目录时的全部信息，也定义在include/linux/fs.h。</p>
<p><strong>4 索引节点操作</strong></p>
<p><strong>5 目录项</strong></p>
<p><strong>6 目录项操作</strong></p>
<p>目录项dentry是对一个文件逻辑属性的描述；</p>
<p><strong>7 文件</strong></p>
<p>文件file是对当前进程打开的文件的描述；</p>
<p><strong>8 文件操作</strong></p>
<p><strong>几个例子</strong> - 1. 多个目录下denrty对应同一个索引节点inode - 2. 文件夹下的nlink代表的是文件夹的子目录数（不包含文件） - 3. 文件的nlink代表的是硬链接数</p>
<h2 id="nfs文件系统">nfs文件系统</h2>
<h3 id="点击查看nfs文件系统"><a href="https://dingpenglong.com/linux_kernel/fs/nfs/nfs">点击查看nfs文件系统</a></h3>
<h2 id="smb文件系统">smb文件系统</h2>
<h2 id="ext2文件系统">ext2文件系统</h2>
</body>
</html>
